package com.xplay.xpocker.message.connecter.mahjong;

import com.xplay.xpocker.business.BusinessEnum;
import com.xplay.xpocker.business.BusinessException;
import com.xplay.xpocker.entity.mahjong.MahjongRoomBuilder;
import com.xplay.xpocker.meta.realize.MahjongRoomEntity;
import com.xplay.xpocker.entity.mahjong.MahjongUserTask;
import com.xplay.xpocker.mapper.SysUserMapper;
import com.xplay.xpocker.meta.MessageContent;
import com.xplay.xpocker.message.connecter.ConnectAnnotation;
import com.xplay.xpocker.message.connecter.ConnectStrategy;
import com.xplay.xpocker.meta.realize.MahjongRule;
import com.xplay.xpocker.meta.realize.MahjongUserChannel;
import com.xplay.xpocker.meta.room.MetaRoomEntity;
import com.xplay.xpocker.meta.user.MetaUserChannel;
import com.xplay.xpocker.observer.SubscriptionSubject;
import com.xplay.xpocker.service.mahjong.IDiskPartService;
import com.xplay.xpocker.socket.UserChannelMate;
import com.xplay.xpocker.util.Assertion;
import com.xplay.xpocker.util.BusinessAssertion;
import com.xplay.xpocker.util.DictionaryConst;
import com.xplay.xpocker.util.SpringContextHolder;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

import static com.xplay.xpocker.util.DictionaryConst.MahjongAction.*;

/**
 * @author wanjie
 * @date 2021/3/28 16:10
 */
@ConnectAnnotation(action = DictionaryConst.RoomTypeConst.WZ_MAHJONG)
@Service
public class WzRoomConnect extends ConnectStrategy {
    @Autowired
    private IDiskPartService diskPartService;
    @Autowired
    @Resource
    private SysUserMapper userMapper;


    @Autowired
    @Qualifier(value = "roomActionLock")
    ConcurrentHashMap<String, ReentrantLock> roomActionLock;

    /**
     * 用户连接的时候这里会产生并发
     * <p>
     * 最开始的想法是  synchronized  但是鉴于 对象锁会降低性能 不是所有房间都用一把锁
     * <p>
     * 改为 ReentrantLock  配合   ConcurrentHashMap 实现一个房间一把锁
     *
     * @param ctx
     */
    @Override
    public MetaRoomEntity doOneMoreThing(ChannelHandlerContext ctx, MetaRoomEntity metaRoom, boolean firstConnection) {
        MahjongRoomEntity roomInfo = null;
        if (metaRoom instanceof MahjongRoomEntity) {
            roomInfo = (MahjongRoomEntity) metaRoom;
        } else {
            roomInfo = (MahjongRoomEntity) metaRoom.getRoomInfo(MahjongRoomEntity.class);
        }
        ArrayList<MahjongUserTask> roomTask = roomInfo.getRoomTask();
        if (null == roomTask) {
            roomTask = new ArrayList<MahjongUserTask>();
            roomInfo.setRoomTask(roomTask);
        }
        // 这里只有新用户加入才刷新房间
        if (firstConnection) {
            updateRoomInfo(roomInfo);
        }
        // 当所有人齐了过后 添加准备操作
        if (firstConnection && roomInfo.getState() == DictionaryConst.MahjongRoomState.CREATE && roomInfo.getRule().getUserCount() == roomInfo.getAllUserInfo().size()) {
            HashMap<String, MahjongUserChannel> allUserInfo = roomInfo.getAllUserInfo();
            for (Map.Entry<String, MahjongUserChannel> entry : allUserInfo.entrySet()) {
                MahjongUserTask task = new MahjongUserTask(entry.getKey(), USER_PREPARE);
                task.setDealWith(false);
                roomInfo.addTask(task);
            }
            if (firstConnection) {
                updateRoomInfo(roomInfo);
            }
            return roomInfo;
        } else {

            // 当用户重新加入牌局  构建用户需要的信息
            // 如果用户是重新加入房间的话   得给用户发送以下信息
            /**
             * 1 剩余的总牌数量
             * 2 其余玩家的碰牌和杠牌和出的牌 以及手牌【数量】
             * 3 当前房间的阻塞信息  如果是自己的话 应该显示 碰杠胡 如果不是自己的话 等待 ...
             */
            log.info("==========update room {}===========", getUserId(ctx));
            senMessage(ctx, new MessageContent(MahjongRoomBuilder.inGame(roomInfo, roomInfo.getUserInfoByUserId(getUserId(ctx))), READ_HOME));
            return roomInfo;
        }
    }
}
